#include "SdkHardware.h"
#include "InSdkIniConfig.h"

Com_s32 Ext_SdkGpio_Export(Com_s32 pin)
{
    Com_s8 path[64];
    Com_s8 buffer[64];
    Com_s32 len;
    Com_s32 fd;

    memset(path, 0, sizeof(path));
    memset(buffer,0,sizeof(buffer));

    sprintf(path, "/sys/class/gpio/gpio%d", pin);
    if(access(path, F_OK) != 0)
    {
        fd = open("/sys/class/gpio/export", O_WRONLY);
        if (fd < 0)
        {
            printf("Failed to open gpio%d export\n",pin);
            return(-1);
        }

        len = snprintf(buffer, sizeof(buffer),"%d",pin);
        if (write(fd, buffer, len) < 0)
        {
            printf("Failed to export gpio%d!\n",pin);
            close(fd);
            return -1;
        }
        close(fd);
    }
    return 0;
}

/* dir: 0-->IN, 1-->OUT */
Com_s32 Ext_SdkGpio_Direction_Set(Com_s32 pin,Com_s32 dir)
{
    const Com_s8 dir_str[] = "in\0out";
    Com_s8 path[64];
    Com_s32 fd;

    memset(path,0,sizeof(path));
    snprintf(path, sizeof(path),"/sys/class/gpio/gpio%d/direction", pin);

    if(access(path, F_OK) == 0)
    {
        fd = open(path, O_WRONLY);
        if (fd < 0) {
            printf("Failed to open gpio%d direction\n",pin);
            return -1;
        }

        if (write(fd, &dir_str[dir == 0 ? 0 : 3], dir == 0 ? 2 : 3) < 0)
        {
            printf("Failed to set gpio%d direction!\n",pin);
            close(fd);
            return -1;
        }
        close(fd);
    }
    return 0;
}

Com_s32 SdkGpio_Unexport(Com_s32 pin)
{
    Com_s8 path[64];
    Com_s8 buffer[64];
    Com_s32 len;
    Com_s32 fd;

    memset(path, 0, sizeof(path));
    memset(buffer,0,sizeof(buffer));

    sprintf(path, "/sys/class/gpio/gpio%d", pin);

    if(access(path, F_OK) == 0)
    {
        fd = open("/sys/class/gpio/unexport", O_WRONLY);
        if (fd < 0)
        {
            printf("Failed to open gpio%d unexport\n",pin);
            return -1;
        }

        len = snprintf(buffer, sizeof(buffer), "%d", pin);
        if (write(fd, buffer, len) < 0) {
            printf("Failed to unexport gpio%d!\n",pin);
            close(fd);
            return -1;
        }
        close(fd);
    }

    return 0;
}

/* value: 0-->LOW, 1-->HIGH */
Com_s32 Ext_SdkGpio_Write(Com_s32 pin, Com_s32 value)
{
    const Com_s8 values_str[] = "01";
    Com_s8 path[64];
    Com_s32 fd;

    memset(path,0,sizeof(path));

    snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);

    if(access(path, F_OK) == 0)
    {
        fd = open(path, O_WRONLY);
        if (fd < 0) {
            printf("Failed to open gpio%d value for writing!\n",pin);
            return -1;
        }

        if (write(fd, &values_str[value == 0 ? 0 : 1], 1) < 0)
        {
            printf("Failed to write gpio%d value!\n",pin);
            close(fd);
            return -1;
        }
        close(fd);
    }
    return 0;
}

Com_s32 Ext_SdkGpio_Read(Com_s32 pin)
{
    Com_s8 path[64];
    Com_s8 value_str[3];
    Com_s32 fd;

    memset(path,0,sizeof(path));
    memset(value_str,0,sizeof(value_str));

    snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);

    if(access(path, F_OK) == 0)
    {
        fd = open(path, O_RDONLY);
        if (fd < 0)
        {
            printf("Failed to open gpio%d value for reading!\n",pin);
            return -1;
        }

        if (read(fd, value_str, 3) < 0)
        {
            printf("Failed to read gpio%d value!\n",pin);
            close(fd);
            return -1;
        }
        close(fd);
        return (atoi(value_str));
    }

    return 0;
}

Com_void Ext_SdkGpio_Init(Com_void)
{
    Ext_SdkGpio_Export(DEF_GPIO_LINK_LED);
    Ext_SdkGpio_Direction_Set(DEF_GPIO_LINK_LED,DEF_SDK_DIR_OUT);
#if CMAKE_LED_ON_LOW_LEVEL
    Ext_SdkGpio_Write(DEF_GPIO_LINK_LED,DEF_COM_LEVEL_LOW);
#else
    Ext_SdkGpio_Write(DEF_GPIO_LINK_LED,DEF_COM_LEVEL_HIGHT);
#endif

    Ext_SdkGpio_Export(DEF_GPIO_SPK);
    Ext_SdkGpio_Direction_Set(DEF_GPIO_SPK,DEF_SDK_DIR_OUT);
    Ext_SdkGpio_Write_Spk(DEF_COM_LEVEL_HIGHT);

    Com_s32 val = Ext_InSdkBasicCfg_GetVal(BASIC_CFG_IRCUT);
    if(val == 1)
    {
        Ext_SdkGpio_Export(DEF_GPIO_IRCUT_N);
        Ext_SdkGpio_Export(DEF_GPIO_IRCUT_P);

        Ext_SdkGpio_Direction_Set(DEF_GPIO_IRCUT_N,DEF_SDK_DIR_OUT);
        Ext_SdkGpio_Direction_Set(DEF_GPIO_IRCUT_P,DEF_SDK_DIR_OUT);

        Ext_SdkGpio_Write(DEF_GPIO_IRCUT_N,DEF_COM_LEVEL_LOW);
        Ext_SdkGpio_Write(DEF_GPIO_IRCUT_P,DEF_COM_LEVEL_LOW);
    }

    Ext_SdkGpio_Export(DEF_GPIO_IR_LED);
    Ext_SdkGpio_Direction_Set(DEF_GPIO_IR_LED,DEF_SDK_DIR_OUT);
    Ext_SdkGpio_Write_IRLed(DEF_COM_LEVEL_LOW);

#if DEF_GPIO_IR_DET
    Ext_SdkGpio_Export(DEF_GPIO_IR_DET);
    Ext_SdkGpio_Direction_Set(DEF_GPIO_IR_DET,DEF_SDK_DIR_IN);
#endif

#if CMAKE_SUPPORT_STEEP_ENGINE
    Ext_SdkGpio_Export(DEF_GPIO_OPEN_STEEP_ENGINE);
    Ext_SdkGpio_Direction_Set(DEF_GPIO_OPEN_STEEP_ENGINE,DEF_SDK_DIR_OUT);
    Ext_SdkGpio_Write(DEF_GPIO_OPEN_STEEP_ENGINE,DEF_COM_LEVEL_LOW);
#endif
}

void Ext_SdkGpio_Write_Led(int value)
{
    Ext_SdkGpio_Write(DEF_GPIO_LINK_LED,value);
}

void Ext_SdkGpio_Write_Burn_UUID_Led(int value)
{
}

void Ext_SdkGpio_Write_Spk(int value)
{
#if CMAKE_SPK_ON_HIGH_LEVEL
    Ext_SdkGpio_Write(DEF_GPIO_SPK,(1 - value));
#else
    Ext_SdkGpio_Write(DEF_GPIO_SPK,value);
#endif
}

void Ext_SdkGpio_Write_IRLed(int value)
{
#if CMAKE_IRLED_ON_LOW_LEVEL
    Ext_SdkGpio_Write(DEF_GPIO_IR_LED, (1 - value));
#else
    Ext_SdkGpio_Write(DEF_GPIO_IR_LED, value);
#endif
}

void Ext_SdkGpio_Write_IRCut(int mode)
{
    Com_s32 val = Ext_InSdkBasicCfg_GetVal(BASIC_CFG_IRCUT);
    if(val == 1)
    {
        val = Ext_InSdkBasicCfg_GetVal(BASIC_CFG_IRCUT_REVERSE);
        if(val == 1)
        {
            if (mode == IRCUT_DAY_MODE)
            {
                Ext_SdkGpio_Write(DEF_GPIO_IRCUT_N,DEF_COM_LEVEL_HIGHT);
                usleep(200 * 1000);
                Ext_SdkGpio_Write(DEF_GPIO_IRCUT_N,DEF_COM_LEVEL_LOW);
            }
            else
            {
                Ext_SdkGpio_Write(DEF_GPIO_IRCUT_P,DEF_COM_LEVEL_HIGHT);
                usleep(200 * 1000);
                Ext_SdkGpio_Write(DEF_GPIO_IRCUT_P,DEF_COM_LEVEL_LOW);
            }
        }
        else
        {
            if (mode == IRCUT_DAY_MODE)
            {
                Ext_SdkGpio_Write(DEF_GPIO_IRCUT_P,DEF_COM_LEVEL_HIGHT);
                usleep(200 * 1000);
                Ext_SdkGpio_Write(DEF_GPIO_IRCUT_P,DEF_COM_LEVEL_LOW);
            }
            else
            {
                Ext_SdkGpio_Write(DEF_GPIO_IRCUT_N,DEF_COM_LEVEL_HIGHT);
                usleep(200 * 1000);
                Ext_SdkGpio_Write(DEF_GPIO_IRCUT_N,DEF_COM_LEVEL_LOW);
            }
        }
    }
}

void Ext_SdkGpio_Write_WatchLed(int value)
{
}

int Ext_SdkGpio_Read_IRDet(void)
{
#if DEF_GPIO_IR_DET
    return Ext_SdkGpio_Read(DEF_GPIO_IR_DET);
#else
    return DEF_COM_SUCCESS;
#endif
}

int Ext_SdkGpio_Read_Adc0(void)
{
    return DEF_COM_SUCCESS;
}

void Ext_SdkGpio_Write_SteepEngine(int value)
{
#if CMAKE_SUPPORT_STEEP_ENGINE
    Ext_SdkGpio_Write(DEF_GPIO_OPEN_STEEP_ENGINE,value);
#endif
}
